package org.osomit.sacct.service.impl;

import org.osomit.sacct.service.iface.GuiceAccountServerService;
import org.osomit.sacct.entity.RequestContext;
import org.osomit.sacct.entity.ApplicationAccount;
import org.osomit.sacct.entity.SessionInfo;
import org.osomit.sacct.entity.WorkflowContext;
import org.osomit.sacct.entity.transfer.SessionHandshakeResponse;
import org.osomit.sacct.account.manager.iface.AccountManager;
import org.osomit.sacct.session.manager.iface.SessionManager;
import org.osomit.sacct.session.token.impl.SessionToken;
import org.osomit.sacct.security.utils.SecurityUtil;
import org.osomit.sacct.security.utils.SharedSecurityGenerator;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

import java.util.List;
import java.io.UnsupportedEncodingException;

import com.google.inject.Inject;

/**
 * @author Jian Fang (John.Jian.Fang@gmail.com)
 * 
 * Date: Jun 27, 2009
 */
public class AccountServerServiceImpl extends BaseServiceImpl implements GuiceAccountServerService {
    public static final String INVALID_REQUEST_ID = "invalid request id";

    private AccountManager accountManager;

    private SessionManager sessionManager;

//    private Log log = LogFactory.getLog(AccountServerServiceImpl.class);

    public AccountManager getAccountManager() {
        return accountManager;
    }

    @Inject
    public void setAccountManager(AccountManager accountManager) {
        this.accountManager = accountManager;
    }

    public SessionManager getSessionManager() {
        return sessionManager;
    }

    @Inject
    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    protected void validateRequestId(WorkflowContext context){
        if(this.sessionManager.isUseOTP()){
            SessionToken stk = this.sessionManager.getToken(context.getSessionId());
            
            String expected = stk.generateOTP();
            if(!expected.equals(context.getRequestId())){
//              log.error(INVALID_REQUEST_ID + ", expected: " + expected + " but actually is " + context.getRequestId());
              throw new SecurityException(INVALID_REQUEST_ID);
            }
        }
    }

    public SessionInfo handshake(RequestContext context, String clientPubKey) {
        SessionHandshakeResponse resp = this.sessionManager.handshake(Base64.decodeBase64(clientPubKey.getBytes()));
        SessionInfo sinfo = new SessionInfo();
        try {
            sinfo.setServerPublicKey(new String(Base64.encodeBase64(resp.getServerPubKeyEnc()), "UTF8"));
        } catch (UnsupportedEncodingException e) {
             e.printStackTrace();
            throw new SecurityException(e.getMessage());
        }
        sinfo.setSessionId(resp.getToken().getId());

        return sinfo;
    }

    public String closeSession(RequestContext context, String goodbye) {
        this.validateRequestId((WorkflowContext)context);

        return SecurityUtil.base64Encode(SharedSecurityGenerator.generateSharedSecret(64));
    }

    public ApplicationAccount fetchAccount(RequestContext context, String account) {
        this.validateRequestId((WorkflowContext)context);

        return this.accountManager.getAccount(context.getClientId(), account);
    }

    public List<ApplicationAccount> fetchAllAccounts(RequestContext context) {
        this.validateRequestId((WorkflowContext)context);
        
        return this.accountManager.getAllAccounts(context.getClientId());
    }

    public String hello(RequestContext context) {
        String resp;
        
        if(context != null && context.getClientId() != null){
            resp = "Hello, " + context.getClientId();
        }else{
            resp = "Hello World";
        }

        return resp;
    }

}
